using Glpt.Common;
using Glpt.CommSearch;
using Glpt.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace GTask
{
    /// <summary>
    /// 任务调度窗体
    /// </summary>
    public partial class FrmMain : Form
    {
        public static int TaskFunctionID = -1;//0全部任务，非0只运行指定任务后退出
        private bool TaskFunctionIDCheck = false;
        private string task_date = "";//任务初始化的日期
        private List<TaskProcessItem> taskProcessList = null;
        private int WaitTaskCount = 0;//当前等待的线程数
        private int ExecTaskCount = 0;//当前执行的线程数
        private CommSearchInfo csinfo = null;
        private Object task_Lock = new Object();
        private delegate void doCallback();
        /// <summary>
        /// 任务总控开关
        /// </summary>
        public bool taskTotalControl = false;
        /// <summary>
        /// 前提任务开关
        /// </summary>
        private bool taskPremiseControl = false;
        //任务调度编号
        private int task_no = 1;
        //最大线程数
        private int MaxTaskCount = 20;
        //任务调度外部前提检测时间间隔
        private int TaskSecond_Out = 5;
        //任务调度内部前提检测时间间隔
        private int TaskSecond_In = 30;
        private bool IsBak = false;//是否是备机
        private int SessionSecond = 300;//会话心跳时间
        private int old_task_no = -1;//原先的任务调度编号

        /// <summary>
        /// 初始化类的新实例
        /// </summary>
        public FrmMain()
        {
            Funcs.AppPath = Application.StartupPath + DataFuns.DirSeparator;
            AbstractInterFace.StartupPath = Funcs.AppPath;
            CommSearchInfo.IsCacheFunctions = false;
            CommTableInfo.IsCacheTables = false;
            InitializeComponent();
        }

        private void FrmMain_Shown(object sender, EventArgs e)
        {
            try
            {
                if (ParamSet.DbName.Length == 0)
                {
                    GClient.FrmParamSet frm = new GClient.FrmParamSet();
                    if (!frm.ShowDialog().Equals(DialogResult.OK))
                    {
                        this.Close();
                        return;
                    }
                }
                if (BaseInterFace.LoginID.Length == 0)
                {
                    GClient.FrmLogin frm = new GClient.FrmLogin();
                    if (!frm.ShowDialog().Equals(DialogResult.OK))
                    {
                        this.Close();
                        return;
                    }
                }
                if (!BaseInterFace.GetLoginName().Equals("admin"))
                {
                    Funcs.ShowTip("非管理员用户，不能启动任务调度！");
                    this.Close();
                    return;
                }
                BaseInterFace gji = new BaseInterFace(ParamSet.GetDbItem());
                if (BaseInterFace.DbList.Count == 0)
                {
                    DataTable dt = gji.GetDbList(1);//获取数据库列表
                    DataTable dtcrypto = gji.GetCrypto(1);
                    foreach (DataRow dr in dt.Rows)
                    {
                        foreach (DataRow dr_crypto in dtcrypto.Rows)
                        {
                            object crypto = InvokeDynamic.CreateObject(dr_crypto["FORWARD_DLL"].ToString());
                            InvokeDynamic.InvokeMember(crypto, new object[] { dr_crypto["KEY1"].ToString(), dr_crypto["KEY2"].ToString() }, "Init");
                            try
                            {
                                dr["USER_PASSWORD"] = InvokeDynamic.InvokeMember(crypto, new object[] { dr["USER_PASSWORD"].ToString() }, "Decrypt");
                            }
                            catch { }
                        }
                        BaseInterFace.DbList.Add(new DbItem(dr));
                    }
                }
                gji = new BaseInterFace();
                DataTable task_process_table = gji.ExecSelect("SELECT * FROM TB_TASK_PROCESS");
                task_process_table.Columns.Add("WaitTaskCount", typeof(int));
                task_process_table.Columns.Add("ExecTaskCount", typeof(int));
                taskProcessList = new List<TaskProcessItem>();
                foreach (DataRow dr in task_process_table.Rows)
                {
                    TaskProcessItem item = new TaskProcessItem(dr);
                    taskProcessList.Add(item);
                }
                dataGridViewTask.AutoGenerateColumns = false;
                dataGridViewTask.DataSource = task_process_table;
                string sNO = ParamList.GetParamData("NO");
                if (sNO.Length == 0)
                {
                    sNO = "1";
                    ParamList.SetParamData("NO", sNO);
                }
                txtNO.Text = sNO;
                string sMaxTaskCount = ParamList.GetParamData("MaxTaskCount");
                if (sMaxTaskCount.Length == 0)
                {
                    sMaxTaskCount = DataDictionary.GetDictParamValue(11);
                    ParamList.SetParamData("MaxTaskCount", sMaxTaskCount);
                }
                txtMaxTaskCount.Text = sMaxTaskCount;
                string sSecondOut = ParamList.GetParamData("SecondOut");
                if (sSecondOut.Length == 0)
                {
                    sSecondOut = DataDictionary.GetDictParamValue(12);
                    ParamList.SetParamData("SecondOut", sSecondOut);
                }
                txtSecondOut.Text = sSecondOut;
                string sSecondIn = ParamList.GetParamData("SecondIn");
                if (sSecondIn.Length == 0)
                {
                    sSecondIn = DataDictionary.GetDictParamValue(13);
                    ParamList.SetParamData("SecondIn", sSecondIn);
                }
                txtSecondIn.Text = sSecondIn;
                string[] funs = DataDictionary.GetDictParamValue(14).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string fun_id in funs)
                {
                    CommSearchControl csc = new CommSearchControl();
                    csc.Dock = DockStyle.Fill;
                    csc.SetParams(fun_id, "0", "5", "0");
                    if (csinfo == null)
                    {
                        csinfo = csc.csinfo;
                        csc.FunctionSearched += new System.EventHandler(this.commSearchControl1_FunctionSearched);
                    }
                    TabPage page = new TabPage(csc.csinfo.CAPTION);
                    page.Controls.Add(csc);
                    tabControl1.TabPages.Add(page);
                }
                ShowTitle();
                if (TaskFunctionID >= 0)
                    btnTotalControl_Click(btnTotalControl, e);
            }
            catch (Exception ex)
            {
                Funcs.ShowError(ex);
                this.Close();
            }
        }

        private void ShowTitle()
        {
            string title = this.Text;
            string sip = ParamSet.GetParamData("ServerIP");
            if (sip.Length > 0)
                title += " - " + sip;
            if (ParamSet.EnableProxy)
                title += " - " + ParamSet.WebServiceProxy;
            this.Text = title;
        }

        private void ShowInfo()
        {
            lock (task_Lock)
            {
                foreach (TaskProcessItem item in taskProcessList)
                {
                    item.DATA_ROW["WaitTaskCount"] = item.WaitTaskCount;
                    item.DATA_ROW["ExecTaskCount"] = item.ExecTaskCount;
                }
            }
        }

        /// <summary>
        /// 总控任务开关
        /// </summary>
        private void btnTotalControl_Click(object sender, EventArgs e)
        {
            try
            {
                if (!taskTotalControl)//当前是关闭状态，现在要开启总控任务开关
                {
                    if (bgWorkerTaskControl.IsBusy)
                    {
                        Funcs.ShowTip("任务控制线程正忙，请稍后再试一下！");
                        return;
                    }
                    else
                    {
                        if (!int.TryParse(txtNO.Text, out task_no))
                        {
                            Funcs.ShowTip("任务调度编号输入错误！");
                            txtNO.Focus();
                            return;
                        }
                        if (!int.TryParse(txtSecondOut.Text, out TaskSecond_Out))
                        {
                            Funcs.ShowTip("外部前提检测时间间隔输入错误！");
                            txtSecondOut.Focus();
                            return;
                        }
                        if (!int.TryParse(txtSecondIn.Text, out TaskSecond_In))
                        {
                            Funcs.ShowTip("内部前提检测时间间隔输入错误！");
                            txtSecondIn.Focus();
                            return;
                        }
                        if (!int.TryParse(txtMaxTaskCount.Text, out MaxTaskCount))
                        {
                            Funcs.ShowTip("最大线程数输入错误！");
                            txtMaxTaskCount.Focus();
                            return;
                        }
                        if (TaskFunctionID <= 0 && (!timerSession.Enabled || task_no != old_task_no))//未开启心跳会话或任务调编号已改变
                        {
                            try
                            {
                                BaseInterFace gji = new BaseInterFace();
                                string sql = "";
                                if (timerSession.Enabled)//之前已开启心跳会话
                                {
                                    timerSession.Enabled = false;
                                    sql = "DELETE FROM TB_TASK_SESSION WHERE SESSION_ID='" + BaseInterFace.LoginID + "'";//删除会话
                                    gji.ExecUpdate(sql);
                                }
                                sql = "SELECT SESSION_ID,TIME_SPAN,UPDATE_TIME,IS_MASTER,GETDATE() AS CUR_TIME FROM TB_TASK_SESSION WHERE TASK_NO=" + task_no.ToString();
                                DataTable dtcheck = gji.ExecSelect(sql);
                                bool has_master = false;
                                foreach (DataRow dr in dtcheck.Rows)
                                {
                                    string SESSION_ID = dr["SESSION_ID"].ToString();
                                    string IS_MASTER = dr["IS_MASTER"].ToString();
                                    int TIME_SPAN = int.Parse(dr["TIME_SPAN"].ToString());
                                    DateTime UPDATE_TIME = (DateTime)dr["UPDATE_TIME"];
                                    DateTime CUR_TIME = (DateTime)dr["CUR_TIME"];
                                    DateTime BakCheckTime = UPDATE_TIME.AddSeconds(TIME_SPAN * 2);
                                    if (BakCheckTime.CompareTo(CUR_TIME) < 0)
                                    {
                                        sql = "DELETE FROM TB_TASK_SESSION WHERE SESSION_ID='" + SESSION_ID + "'";//删除过期的会话
                                        gji.ExecUpdate(sql);
                                    }
                                    else if (IS_MASTER.Equals("1"))
                                        has_master = true;
                                }
                                if (has_master)
                                {
                                    if (Funcs.ShowQuestion("检测到有任务调度(编号:" + task_no.ToString() + ")正式运行，此任务调度要以备机方式运行吗？").Equals(DialogResult.Yes))
                                    {
                                        IsBak = true;
                                        this.Text += " - 备机";
                                    }
                                }
                                else
                                {
                                    IsBak = false;
                                    this.Text = this.Text.Replace(" - 备机", "");
                                }
                                sql = "INSERT INTO TB_TASK_SESSION(SESSION_ID,TASK_NO,IS_MASTER,TIME_SPAN,START_TIME,UPDATE_TIME) VALUES('" + BaseInterFace.LoginID + "'," + task_no.ToString() + ",'" + (IsBak ? "0" : "1") + "'," + SessionSecond.ToString() + ",GETDATE(),GETDATE())";
                                gji.ExecUpdate(sql);//写入心跳会话信息
                                timerSession.Interval = SessionSecond * 1000;
                                timerSession.Enabled = true;//开启心跳会话
                                old_task_no = task_no;
                            }
                            catch { }
                        }
                        labTotalControlStatus.Text = "启动";
                        labTotalControlStatus.ForeColor = Color.Green;
                        btnTotalControl.Text = "停止";
                        txtNO.Enabled = false;
                        txtSecondOut.Enabled = false;
                        txtSecondIn.Enabled = false;
                        txtMaxTaskCount.Enabled = false;
                        taskTotalControl = !taskTotalControl;
                        bgWorkerTaskControl.RunWorkerAsync();
                    }
                }
                else//当前是开启状态，现在要关闭总控任务开关
                {
                    labTotalControlStatus.Text = "停止";
                    labTotalControlStatus.ForeColor = Color.Red;
                    btnTotalControl.Text = "启动";
                    txtNO.Enabled = true;
                    txtSecondOut.Enabled = true;
                    txtSecondIn.Enabled = true;
                    txtMaxTaskCount.Enabled = true;
                    if (bgWorkerTaskControl.IsBusy)
                    {
                        bgWorkerTaskControl.CancelAsync();
                        lock (task_Lock)
                        {
                            foreach (TaskProcessItem pitem in taskProcessList)
                            {
                                foreach (TaskItem titem in pitem.EXEC_LIST)//获取正在执行的任务列表
                                {
                                    titem.bgw.CancelAsync();//杀线程
                                    BaseInterFace.CancelCommand(titem.bgw);//取消正在执行的数据库SQL命令
                                }
                            }
                        }
                    }
                    taskTotalControl = !taskTotalControl;
                }
                RunCheckPremise(taskTotalControl);
            }
            catch (Exception ex)
            {
                Funcs.ShowError(ex);
            }
        }

        private void timerSession_Tick(object sender, EventArgs e)
        {
            try
            {
                BaseInterFace gji = new BaseInterFace();
                string sql = "UPDATE TB_TASK_SESSION SET UPDATE_TIME=GETDATE() WHERE SESSION_ID='" + BaseInterFace.LoginID + "'";//更新心跳时间
                gji.ExecUpdate(sql);
                if (IsBak)//如果是备机
                {
                    sql = "SELECT SESSION_ID,TIME_SPAN,UPDATE_TIME,GETDATE() AS CUR_TIME FROM TB_TASK_SESSION WHERE TASK_NO=" + task_no.ToString() + " AND IS_MASTER='1'";
                    DataTable dtcheck = gji.ExecSelect(sql);
                    if (dtcheck.Rows.Count > 0)
                    {
                        string SESSION_ID = dtcheck.Rows[0]["SESSION_ID"].ToString();
                        int TIME_SPAN = int.Parse(dtcheck.Rows[0]["TIME_SPAN"].ToString());
                        DateTime UPDATE_TIME = (DateTime)dtcheck.Rows[0]["UPDATE_TIME"];
                        DateTime CUR_TIME = (DateTime)dtcheck.Rows[0]["CUR_TIME"];
                        DateTime BakCheckTime = UPDATE_TIME.AddSeconds(TIME_SPAN * 2);
                        if (BakCheckTime.CompareTo(CUR_TIME) < 0)//主机的心跳时间超过2倍的间隔时间
                        {
                            sql = "UPDATE TB_TASK_SESSION SET IS_MASTER='1' WHERE SESSION_ID='" + BaseInterFace.LoginID + "'";//把自己变更成主机
                            gji.ExecUpdate(sql);
                            sql = "DELETE FROM TB_TASK_SESSION WHERE SESSION_ID='" + SESSION_ID + "'";//删除过期会话
                            gji.ExecUpdate(sql);
                            sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='0',ERROR_TIMES=99 where EXECUTED_FLAG='1' AND FUNCTION_ID IN (select FUNCTION_ID from TB_TASK_FUNCTION A INNER JOIN TB_TASK_GROUP B ON A.TASK_GROUP_ID=B.TASK_GROUP_ID where COALESCE(A.TASK_NO,B.TASK_NO)=" + task_no.ToString() + ")";
                            gji.ExecUpdate(sql);//把执行中的任务状态改为未执行
                            gji.SaveSysLog("", "任务调度(编号:" + task_no.ToString() + ")由备机变成主机");
                            IsBak = false;//取消备机标志
                            this.Text = this.Text.Replace(" - 备机", "");
                        }
                    }
                }
            }
            catch { }
        }
        /// <summary>
        /// 前提检测线程开关
        /// </summary>
        private void btnCheckPremise_Click(object sender, EventArgs e)
        {
            try
            {
                RunCheckPremise(!taskPremiseControl);
            }
            catch (Exception ex)
            {
                Funcs.ShowError(ex);
            }
        }
        /// <summary>
        /// 前提检测线程开关
        /// </summary>
        /// <param name="isrun">是否启动</param>
        private void RunCheckPremise(bool isrun)
        {
            if (isrun)
            {
                if (!taskTotalControl) return;
                labCheckPremiseOut.Text = "";
                if (TaskSecond_Out > 0 && TaskFunctionID <= 0)
                {
                    timerCheckPremiseOut.Interval = 500;
                    timerCheckPremiseOut.Start();
                }
                labCheckPremiseIn.Text = "";
                if (TaskSecond_In > 0)
                {
                    timerCheckPremiseIn.Interval = 5000;
                    timerCheckPremiseIn.Start();
                }
                labCheckPremiseStatus.Text = "启动";
                labCheckPremiseStatus.ForeColor = Color.Green;
                btnCheckPremise.Text = "停止";
            }
            else
            {
                timerCheckPremiseOut.Stop();
                timerCheckPremiseIn.Stop();
                labCheckPremiseStatus.Text = "停止";
                labCheckPremiseStatus.ForeColor = Color.Red;
                btnCheckPremise.Text = "启动";
            }
            taskPremiseControl = isrun;
        }
        /// <summary>
        /// 外部前提检测线程时钟
        /// </summary>
        private void timerCheckPremiseOut_Tick(object sender, EventArgs e)
        {
            try
            {
                timerCheckPremiseOut.Interval = 1000 * 60 * TaskSecond_Out;
                if (!bgWorkerCheckPremiseOut.IsBusy)
                {
                    labCheckPremiseOut.Text = "外部：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    bgWorkerCheckPremiseOut.RunWorkerAsync();
                }
            }
            catch (Exception ex)
            {
                labCheckPremiseOut.Text = DateTime.Now.ToString() + ex.Message;
                RunCheckPremise(true);
            }
        }
        /// <summary>
        /// 内部前提检测线程时钟
        /// </summary>
        private void timerCheckPremiseIn_Tick(object sender, EventArgs e)
        {
            try
            {
                timerCheckPremiseIn.Interval = 1000 * TaskSecond_In;
                if (!bgWorkerCheckPremiseIn.IsBusy)
                {
                    if (TaskFunctionID > 0 && TaskFunctionIDCheck)
                    {
                        btnCheckPremise_Click(btnCheckPremise, null);
                    }
                    else
                    {
                        labCheckPremiseIn.Text = "内部：" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                        TaskFunctionIDCheck = true;
                        bgWorkerCheckPremiseIn.RunWorkerAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                labCheckPremiseIn.Text = DateTime.Now.ToString() + ex.Message;
                RunCheckPremise(true);
            }
        }
        /// <summary>
        /// 外部前提检测线程
        /// </summary>
        private void bgWorkerCheckPremiseOut_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                if (IsBak) return;//备机不做前提检
                StringBuilder sbuf = new StringBuilder();
                string sql = "PR_TASK_CHECK_PREMISE";
                DbParamCollection sql_params = new DbParamCollection();
                sql_params.Add(new DbParam("i_tradedate", task_date, DbParamType.VarChar, false));
                sql_params.Add(new DbParam("o_tradedate", DBNull.Value, DbParamType.VarChar, true));
                sql_params.Add(new DbParam("i_task_no", task_no, DbParamType.Int, false));
                BaseInterFace gji = new BaseInterFace();
                DataTable dt = gji.ExecSelect(sender, sql, sql_params, true, -1);//执行外部前提检测，获取需要在任务调度里检测的清单
                task_date = sql_params[1].Value.ToString();
                Exception ex_inner = null;
                foreach (DataRow dr in dt.Rows)
                {
                    DateTime dt_begin = DateTime.Now;
                    if (!dt.Columns.Contains("CHECK_FUNC_SQL_G"))
                        break;
                    string CHECK_FUNC_SQL_G = dr["CHECK_FUNC_SQL_G"].ToString();
                    string TRADEDATE = dr["TRADEDATE"].ToString();
                    string forwarddll = CHECK_FUNC_SQL_G;
                    int idx = forwarddll.IndexOf("#");
                    object[] execParams = new object[] { TRADEDATE };
                    if (idx > 0)
                    {
                        forwarddll = CHECK_FUNC_SQL_G.Substring(0, idx);
                        execParams = DataFuns.SplitString(Funcs.ReplaceWord(CHECK_FUNC_SQL_G.Substring(idx + 1), TRADEDATE), ',', true).ToArray();//分解参数
                    }
                    object obj = null;
                    if (forwarddll.Equals("?"))
                        obj = new CheckPremise();//以?#开头的，调用默认的前提检测对象
                    else
                        obj = InvokeDynamic.CreateObject(forwarddll);//利用反射，动态加载自定义的前提检测对象
                    try
                    {
                        object val = InvokeDynamic.InvokeMember(obj, execParams);//利用反射，动态执行前提检测对象的SetParams函数
                        if (val != null && val.ToString().Equals("1"))//返回值是1
                        {
                            int CHECK_TYPE = int.Parse(dr["CHECK_TYPE"].ToString());
                            if (CHECK_TYPE == 1 || CHECK_TYPE == 3)//要清空前提组的函数
                            {
                                sql = "update TB_TASK_LIST set CHECK_FUNC_SQL_G=null where TRADEDATE=" + gji.ParamChar + "tradedate and CHECK_FUNC_SQL_G=" + gji.ParamChar + "check_func_sql";
                                sql_params.Clear();
                                sql_params.Add(new DbParam("tradedate", TRADEDATE, DbParamType.VarChar, false));
                                sql_params.Add(new DbParam("check_func_sql", CHECK_FUNC_SQL_G, DbParamType.VarChar, false));
                                gji.ExecUpdate(sql, sql_params);
                            }
                            if (CHECK_TYPE == 2 || CHECK_TYPE == 3)//要清空前提功能的函数
                            {
                                sql = "update TB_TASK_LIST set CHECK_FUNC_SQL_F=null where TRADEDATE=" + gji.ParamChar + "tradedate and CHECK_FUNC_SQL_F=" + gji.ParamChar + "check_func_sql";
                                sql_params.Clear();
                                sql_params.Add(new DbParam("tradedate", TRADEDATE, DbParamType.VarChar, false));
                                sql_params.Add(new DbParam("check_func_sql", CHECK_FUNC_SQL_G, DbParamType.VarChar, false));
                                gji.ExecUpdate(sql, sql_params);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ex_inner = ex;
                    }
                    finally
                    {
                        InvokeDynamic.InvokeMember(obj, null, "Dispose");
                    }
                    if (TaskSecond_Out == 999)//当等于999时，启用前提检测的日志功能
                    {
                        DateTime dt_end = DateTime.Now;
                        sbuf.Append(dt_begin.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                        sbuf.Append(",");
                        sbuf.Append(dt_end.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                        sbuf.Append(",");
                        sbuf.Append((dt_end - dt_begin).ToString());
                        sbuf.Append(",");
                        sbuf.Append(TRADEDATE);
                        sbuf.Append(",");
                        sbuf.AppendLine(CHECK_FUNC_SQL_G);
                    }
                }
                if (sbuf.Length > 0)
                    System.IO.File.AppendAllText(AbstractInterFace.StartupPath + DataFuns.DirSeparator + "PREMISE.log", sbuf.ToString());
                if (ex_inner != null) throw new Exception(ex_inner.Message, ex_inner);
            }
            catch
            {
                if (!bgWorkerCheckPremiseOut.CancellationPending) throw;
            }
            finally
            {
                if (bgWorkerCheckPremiseOut.CancellationPending) e.Cancel = true;
            }
        }
        /// <summary>
        /// 内部前提检测线程
        /// </summary>
        private void bgWorkerCheckPremiseIn_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                if (IsBak) return;//备机不做前提检
                string sql = "";
                DbParamCollection sql_params = new DbParamCollection();
                DataTable dt = null;
                if (TaskFunctionID > 0)//外部有传入功能号，则只检测该功能号的任务
                {
                    sql = "select TASK_ID," + taskProcessList[0].PROCESS_ID + " AS PROCESS_ID from TB_TASK_LIST where FUNCTION_ID=@FUNCTION_ID AND EXECUTED_FLAG='0' AND ENABLE_FLAG='1'";
                    sql_params.Add(new DbParam("FUNCTION_ID", TaskFunctionID, DbParamType.Int, false));
                    dt = new BaseInterFace().ExecSelect(sql, sql_params);
                    if (dt.Rows.Count == 0) backgroundWorkerTask_Completed();
                }
                else//否则调用存储过程检测
                {
                    sql = "PR_TASK_CHECK_LIST";
                    sql_params.Add(new DbParam("i_task_no", task_no, DbParamType.Int, false));
                    dt = new BaseInterFace().ExecSelect(sender, sql, sql_params, true, -1);
                }
                lock (task_Lock)
                {
                    foreach (DataRow dr in dt.Rows)
                    {
                        TaskItem titem = new TaskItem(dr);
                        foreach (TaskProcessItem item in taskProcessList)
                        {
                            if (item.PROCESS_ID.Equals(titem.PROCESS_ID))
                            {
                                TaskItemCollection wait_list = item.WAIT_LIST;
                                TaskItemCollection exec_list = item.EXEC_LIST;
                                if (wait_list[titem.TASK_ID] == null && exec_list[titem.TASK_ID] == null)
                                {
                                    wait_list.Add(titem);//把任务添加到等待队列
                                    WaitTaskCount++;
                                }
                            }
                        }
                    }
                }
            }
            catch
            {
                if (!bgWorkerCheckPremiseIn.CancellationPending) throw;
            }
            finally
            {
                if (bgWorkerCheckPremiseIn.CancellationPending) e.Cancel = true;
            }
        }

        private void bgWorkerCheckPremiseOut_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                ShowInfo();
                labCheckPremiseOut.Text += " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                if (e.Cancelled)
                {
                    return;
                }
                if (e.Error != null)
                {
                    labCheckPremiseOut.Text += DateTime.Now.ToString() + e.Error.Message;
                    Funcs.WriteErrorLog(e.Error);
                    return;
                }
            }
            catch (Exception ex)
            {
                Funcs.WriteErrorLog(ex);
            }
        }

        private void bgWorkerCheckPremiseIn_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                ShowInfo();
                labCheckPremiseIn.Text += " - " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                if (e.Cancelled)
                {
                    return;
                }
                if (e.Error != null)
                {
                    if (e.Error.Message.Equals("exit"))
                    {
                        taskTotalControl = false;
                        Application.Exit();
                    }
                    else
                    {
                        labCheckPremiseIn.Text += DateTime.Now.ToString() + e.Error.Message;
                        Funcs.WriteErrorLog(e.Error);
                    }
                    return;
                }
            }
            catch (Exception ex)
            {
                Funcs.WriteErrorLog(ex);
            }
        }
        /// <summary>
        /// 任务控制线程
        /// </summary>
        private void bgWorkerTaskControl_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                while (!bgWorkerTaskControl.CancellationPending && taskTotalControl)//总控开关是开启状态
                {
                    try
                    {
                        if (WaitTaskCount > 0 && ExecTaskCount < MaxTaskCount && taskPremiseControl)//有任务在等待，并且执行的线程数小于最大线程数，并且前提检测开关是开启状态
                        {
                            lock (task_Lock)//任务队列加锁
                            {
                                foreach (TaskProcessItem item in taskProcessList)//逐个队列窗口检测
                                {

                                    TaskItemCollection wait_list = item.WAIT_LIST;
                                    TaskItemCollection exec_list = item.EXEC_LIST;
                                    if (item.WaitTaskCount > 0 && item.ExecTaskCount < item.MAX_THREAD_COUNT)//当前队列窗口有任务在等待，并且执行的线程数小于队列窗口最大线程数
                                    {
                                        TaskItem titem = wait_list[0];//取等待队列的第一个任务
                                        BackgroundWorker backTask = new BackgroundWorker();//创建一个后台线程
                                        backTask.WorkerReportsProgress = true;
                                        backTask.WorkerSupportsCancellation = true;
                                        backTask.DoWork += new DoWorkEventHandler(backgroundWorkerTask_DoWork);
                                        backTask.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorkerTask_RunWorkerCompleted);
                                        wait_list.Remove(titem);//把它从等待队列中移除
                                        WaitTaskCount--;//等待任务数减1
                                        exec_list.Add(titem);//把它加入到执行队列中
                                        ExecTaskCount++;//执行任务数加1
                                        titem.bgw = backTask;//指定任务对应的线程
                                        bgWorkerTaskControl.ReportProgress(1);
                                        backTask.RunWorkerAsync(titem);//启动线程，开始执行
                                        System.Threading.Thread.Sleep(10);//当前的任务控制线程休息10毫秒后，才能启动下一个线程
                                    }
                                }
                            }
                            System.Threading.Thread.Sleep(10);//休息10毫秒
                        }
                        else
                            System.Threading.Thread.Sleep(500);//没有任务，或线程总数已超过最大线程数，休息500毫秒
                    }
                    catch
                    {
                        System.Threading.Thread.Sleep(500);
                    }
                }
            }
            catch
            {
                if (!bgWorkerTaskControl.CancellationPending) throw;
            }
            finally
            {
                if (bgWorkerTaskControl.CancellationPending) e.Cancel = true;
            }
        }
        /// <summary>
        /// 任务控制线程
        /// </summary>
        private void bgWorkerTaskControl_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                ShowInfo();
            }
            catch (Exception ex)
            {
                labTotalControl.Text = DateTime.Now.ToString() + ex.Message;
            }
        }
        /// <summary>
        /// 任务控制结束线程
        /// </summary>
        private void bgWorkerTaskControl_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                ShowInfo();
                if (e.Cancelled)
                {
                    return;
                }
                if (e.Error != null)
                {
                    labTotalControl.Text = DateTime.Now.ToString() + e.Error.Message;
                    return;
                }
            }
            catch (Exception ex)
            {
                Funcs.WriteErrorLog(ex);
            }
        }
        /// <summary>
        /// 任务执行线程
        /// </summary>
        private void backgroundWorkerTask_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker backgroundWorkerTask = (BackgroundWorker)sender;
            try
            {
                TaskItem titem = (TaskItem)e.Argument;
                BaseInterFace gji = new BaseInterFace();
                DbParamCollection sql_params = new DbParamCollection();
                sql_params.Add(new DbParam("i_task_id", titem.TASK_ID, DbParamType.Double, false));
                string sql = "PR_TASK_LIST_PARAMS";
                DataTable dt = gji.ExecSelect(null, sql, sql_params, true, -1);//检测，并获取实例化后的任务列表信息
                if (dt.Rows.Count > 0)
                {
                    DataRow dr = dt.Rows[0];
                    sql = "SELECT PROC_NAME FROM TB_TASK_FUNCTION WHERE FUNCTION_ID=" + dr["FUNCTION_ID"].ToString();
                    DataTable dt_proc_name = gji.ExecSelect(sql);//获取任务功能定义
                    if (dt_proc_name.Rows.Count > 0)
                    {
                        DbItem dbi = BaseInterFace.DbList.GetByNo(int.Parse(dr["DB_NO"].ToString()));//获取指向的数据库
                        if (dbi != null)
                        {
                            try
                            {
                                string proc_name = dt_proc_name.Rows[0][0].ToString();
                                string TRADEDATE = dr["TRADEDATE"].ToString();
                                string PARAM_VALUE = dr["PARAM_VALUE"].ToString();
                                sql = "SELECT PARAM_NAME,PARAM_VALUE FROM TB_TASK_FUNCTION_PARMS WHERE FUNCTION_ID=" + gji.ParamChar + "function_id ORDER BY PARAM_SEQ";//获取任务的个性化参数定义
                                sql_params.Clear();
                                sql_params.Add(new DbParam("function_id", dr["FUNCTION_ID"], DbParamType.Int, false));
                                DataTable dt_function_params = gji.ExecSelect(sql, sql_params);
                                sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='1',EXECUTE_START_TIME=GETDATE() WHERE EXECUTED_FLAG<>'1' AND TASK_ID=" + titem.TASK_ID;
                                int update_rows = gji.ExecUpdate(sql);//把任务从未执行的状态变更为正在执行
                                if (update_rows == 0) return;//如果没有更新成功，说明任务被别的任务调度取走，直接退出线程
                                if (proc_name.IndexOf('?') > 0)//调用DLL
                                {
                                    int idx = proc_name.IndexOf("#");
                                    string[] strParams = new string[0];
                                    if (idx > 0)
                                    {
                                        strParams = Funcs.ReplaceWord(proc_name.Substring(idx + 1), TRADEDATE).Split(new char[] { ',' }, StringSplitOptions.None);//拆分参数
                                        proc_name = proc_name.Substring(0, idx);
                                    }
                                    object[] dllParams = new object[strParams.Length + dt_function_params.Rows.Count];
                                    for (int i = 0; i < strParams.Length; i++)
                                    {
                                        dllParams[i] = strParams[i];
                                    }
                                    int param_count = strParams.Length;//参数个数
                                    foreach (DataRow drparam in dt_function_params.Rows)
                                    {
                                        dllParams[param_count++] = GetParamValue(drparam["PARAM_VALUE"].ToString(), dr);//从实例化的任务列表信息中获取参数值
                                    }
                                    param_count = 4;//默认参数个数
                                    if (PARAM_VALUE.Length > 0) param_count++;
                                    object[] execParams = new object[param_count];
                                    execParams[0] = dbi.DB_NO;
                                    execParams[1] = dr["FUNCTION_ID"].ToString();
                                    execParams[2] = dr["TASK_ID"].ToString();
                                    execParams[3] = TRADEDATE;
                                    if (PARAM_VALUE.Length > 0) execParams[4] = PARAM_VALUE;//如果是任务分拆，则参数值字段不为空，再增加一个参数值
                                    object obj = InvokeDynamic.CreateObject(proc_name);//利用反射，动态调用任务对象
                                    try
                                    {
                                        InvokeDynamic.SetPropertyInfo(obj, "BackgroundWorkerTask", backgroundWorkerTask);//利用反射，动态设置对应的线程
                                        if (dllParams.Length > 0)
                                            InvokeDynamic.InvokeMember(obj, dllParams);//如果有定义个性化参数，利用反射，动态执行SetParams函数
                                        InvokeDynamic.InvokeMember(obj, execParams);//利用反射，动态执行SetParams函数
                                    }
                                    finally
                                    {
                                        InvokeDynamic.InvokeMember(obj, null, "Dispose");
                                        GC.Collect();
                                    }
                                }
                                else//调用存储过程
                                {
                                    sql_params.Clear();
                                    sql_params.Add(new DbParam("tradedate", TRADEDATE, DbParamType.VarChar, false));//至少有一个日期参数
                                    if (PARAM_VALUE.Length > 0)//如果是任务分拆，则参数值字段不为空
                                        sql_params.Add(new DbParam("param_value", PARAM_VALUE, DbParamType.VarChar, false));//再增加一个参数值
                                    foreach (DataRow drparam in dt_function_params.Rows)//如果有个性化参数
                                    {
                                        string param_val = GetParamValue(drparam["PARAM_VALUE"].ToString(), dr).Trim();//从实例化的任务列表信息中获取参数值
                                        bool out_flag = (param_val.Length == 0);//没有值，表示输出参数
                                        sql_params.Add(new DbParam(drparam["PARAM_NAME"].ToString(), param_val, DbParamType.VarChar, out_flag));
                                    }
                                    new BaseInterFace(dbi).ExecUpdate(backgroundWorkerTask, proc_name, sql_params, true);//执行存储过程
                                }
                                sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='2',EXECUTE_END_TIME=GETDATE() WHERE EXECUTED_FLAG='1' AND TASK_ID=" + titem.TASK_ID;
                                gji.ExecUpdate(sql);//把任务状态修改为执行成功
                            }
                            catch (Exception proc_ex)
                            {
                                sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='3',ERROR_TIMES=ERROR_TIMES+1,EXECUTE_END_TIME=GETDATE() WHERE EXECUTED_FLAG='1' AND TASK_ID=" + titem.TASK_ID;
                                gji.ExecUpdate(sql);//把任务状态修改为执行失败，并错误次数加1
                                try
                                {
                                    object onum = InvokeDynamic.GetPropertyInfo(proc_ex, "Number");//利用反射，获取错误对象的错误编号
                                    string snum = "0";
                                    if (onum != null) snum = onum.ToString();
                                    sql = "INSERT INTO TB_TASK_LOG(TASK_ID,EXECUTE_TIME,ERROR_SQLCODE,ERROR_SQLERRM) VALUES(" + titem.TASK_ID + ",GETDATE()," + snum + "," + gji.ParamChar + "ERROR_SQLERRM)";
                                    DbParamCollection log_params = new DbParamCollection();
                                    string msg = proc_ex.Message;
                                    int imax = 4000;
                                    if (msg.Length > imax)
                                    {
                                        int idx = msg.IndexOf("\r");
                                        if (idx <= 0 || idx > imax)
                                            idx = imax;
                                        msg = msg.Substring(0, idx);
                                    }
                                    log_params.Add(new DbParam("ERROR_SQLERRM", msg, DbParamType.VarChar, false));
                                    gji.ExecUpdate(sql, log_params);//写入日志表
                                }
                                catch (Exception log_ex)
                                {
                                    Funcs.WriteErrorLog(log_ex);
                                }
                                Funcs.WriteErrorLog(proc_ex);//写错误日志到文件
                            }
                        }
                        else//没有找到指向的数据库
                        {
                            sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='3',ERROR_TIMES=3,EXECUTE_END_TIME=GETDATE() WHERE TASK_ID=" + titem.TASK_ID;
                            gji.ExecUpdate(sql);
                            sql = "INSERT INTO TB_TASK_LOG(TASK_ID,EXECUTE_TIME,ERROR_SQLCODE,ERROR_SQLERRM) VALUES(" + titem.TASK_ID + ",GETDATE(),0,'找不到编号为" + dr["DB_NO"].ToString() + "的数据库')";
                            gji.ExecUpdate(sql);
                        }
                    }
                }
            }
            catch
            {
                if (!backgroundWorkerTask.CancellationPending) throw;
            }
            finally
            {
                if (backgroundWorkerTask.CancellationPending) e.Cancel = true;
            }
        }
        private string GetParamValue(string sval, DataRow dr)
        {
            if (sval.StartsWith("@"))
            {
                string field_name = sval.Substring(1);
                if (dr.Table.Columns.Contains(field_name))
                    return dr[field_name].ToString();
                else
                    return sval;
            }
            else
                return sval;
        }
        /// <summary>
        /// 任务执行结束线程
        /// </summary>
        private void backgroundWorkerTask_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                BackgroundWorker backgroundWorkerTask = (BackgroundWorker)sender;
                lock (task_Lock)
                {
                    foreach (TaskProcessItem pitem in taskProcessList)
                    {
                        TaskItemCollection exec_list = pitem.EXEC_LIST;
                        TaskItem titem = exec_list[backgroundWorkerTask];
                        if (titem != null)
                        {
                            exec_list.Remove(titem);
                            ExecTaskCount--;
                        }
                    }
                }
                backgroundWorkerTask_Completed();
            }
            catch (Exception ex)
            {
                Funcs.WriteErrorLog(ex);
            }
        }

        private void backgroundWorkerTask_Completed()
        {
            if (this.InvokeRequired)
            {
                doCallback dcb = new doCallback(backgroundWorkerTask_Completed);
                this.Invoke(dcb);
                return;
            }
            ShowInfo();
            if (TaskFunctionID > 0 && ExecTaskCount == 0 && WaitTaskCount == 0)
            {
                System.Threading.Thread.Sleep(1000);
                taskTotalControl = false;
                Application.Exit();
            }
        }

        private void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            e.Cancel = true;
        }

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                bool is_change = false;
                if (txtNO.Text.Length > 0 && !ParamList.GetParamData("NO").Equals(txtNO.Text))
                {
                    ParamList.SetParamData("NO", txtNO.Text);
                    is_change = true;
                }
                if (txtMaxTaskCount.Text.Length > 0 && !ParamList.GetParamData("MaxTaskCount").Equals(txtMaxTaskCount.Text))
                {
                    ParamList.SetParamData("MaxTaskCount", txtMaxTaskCount.Text);
                    is_change = true;
                }
                if (txtSecondOut.Text.Length > 0 && !ParamList.GetParamData("SecondOut").Equals(txtSecondOut.Text))
                {
                    ParamList.SetParamData("SecondOut", txtSecondOut.Text);
                    is_change = true;
                }
                if (txtSecondIn.Text.Length > 0 && !ParamList.GetParamData("SecondIn").Equals(txtSecondIn.Text))
                {
                    ParamList.SetParamData("SecondIn", txtSecondIn.Text);
                    is_change = true;
                }
                if (is_change)
                    ParamList.Save();
                if (taskTotalControl || ExecTaskCount > 0)
                {
                    if (Funcs.ShowQuestion("正在执行,确实要退出吗?", MessageBoxButtons.OKCancel).Equals(DialogResult.OK))
                    {
                        taskTotalControl = false;
                        if (bgWorkerCheckPremiseOut.IsBusy)
                            bgWorkerCheckPremiseOut.CancelAsync();//取消线程
                        if (bgWorkerTaskControl.IsBusy)
                            bgWorkerTaskControl.CancelAsync();//取消线程
                        string task_ids = "";
                        lock (task_Lock)
                        {
                            foreach (TaskProcessItem pitem in taskProcessList)
                            {
                                foreach (TaskItem titem in pitem.EXEC_LIST)
                                {
                                    //titem.bgw.CancelAsync();
                                    //BaseInterFace.CancelCommand(titem.bgw);
                                    task_ids += "," + titem.TASK_ID;
                                }
                            }
                        }
                        if (task_ids.Length > 0)
                        {
                            string sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='0',ERROR_TIMES=ERROR_TIMES+1 where EXECUTED_FLAG='1' and TASK_ID in (" + task_ids.Substring(1) + ")";
                            new BaseInterFace().ExecUpdate(sql);//把正在执行的任务状态改为未执行
                        }
                    }
                    else
                    {
                        e.Cancel = true;
                    }
                }
                if (timerSession.Enabled)
                {
                    string sql = "DELETE FROM TB_TASK_SESSION WHERE SESSION_ID='" + BaseInterFace.LoginID + "'";
                    new BaseInterFace().ExecUpdate(sql);//删除心跳会话
                }
            }
            catch { }
        }
        /// <summary>
        /// 手工重新执行任务
        /// </summary>
        private void MenuItemReDo_Click(object sender, EventArgs e)
        {
            try
            {
                if (csinfo == null || csinfo.DataGrid.CurrentRow == null) return;
                DataRowView drv = (DataRowView)csinfo.DataGrid.CurrentRow.DataBoundItem;
                string task_id = drv["TASK_ID"].ToString();
                string sql = "UPDATE TB_TASK_LIST SET EXECUTED_FLAG='0' where EXECUTED_FLAG<>'0' and TASK_ID=" + task_id;
                new BaseInterFace().ExecUpdate(sql);
                drv.Row["EXECUTED_FLAG"] = "0";
            }
            catch (Exception ex)
            {
                Funcs.ShowError(ex);
            }
        }

        /// <summary>
        /// 手工取消执行任务
        /// </summary>
        private void MenuItemCancelDo_Click(object sender, EventArgs e)
        {
            try
            {
                if (csinfo == null || csinfo.DataGrid.CurrentRow == null) return;
                DataRowView drv = (DataRowView)csinfo.DataGrid.CurrentRow.DataBoundItem;
                string task_id = drv["TASK_ID"].ToString();
                lock (task_Lock)
                {
                    foreach (TaskProcessItem pitem in taskProcessList)
                    {
                        foreach (TaskItem titem in pitem.EXEC_LIST)
                        {
                            if (titem.TASK_ID.Equals(task_id))
                            {
                                if (titem.bgw != null && titem.bgw.IsBusy)
                                {
                                    titem.bgw.CancelAsync();
                                    BaseInterFace.CancelCommand(titem.bgw);
                                }
                                return;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Funcs.ShowError(ex);
            }
        }

        private void commSearchControl1_FunctionSearched(object sender, EventArgs e)
        {
            if (csinfo != null && csinfo.DataGrid.Columns.Contains("EXECUTED_FLAG"))
            {
                csinfo.DataGrid.Columns["EXECUTED_FLAG"].ContextMenuStrip = contextMenuStrip1;
            }
        }
    }
}